package cn.com.utt.unms.service.impl;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.com.utt.common.exception.RPCException;
import cn.com.utt.common.http.Client;
import cn.com.utt.common.log.doLog;
import cn.com.utt.common.message.Command;
import cn.com.utt.common.message.Disconnect;
import cn.com.utt.common.message.Download;
import cn.com.utt.common.message.DownloadResp;
import cn.com.utt.common.message.Get;
import cn.com.utt.common.message.GetResp;
import cn.com.utt.common.message.GetXml;
import cn.com.utt.common.message.GetXmlResp;
import cn.com.utt.common.message.Message;
import cn.com.utt.common.message.Reboot;
import cn.com.utt.common.message.RebootResp;
import cn.com.utt.common.message.Reset;
import cn.com.utt.common.message.ResetResp;
import cn.com.utt.common.message.Set;
import cn.com.utt.common.proto.ServiceZone;
import cn.com.utt.common.proto.ServiceZone.RateLimit;
import cn.com.utt.common.proto.ServiceZone.Wep;
import cn.com.utt.common.proto.ServiceZone.Wep.Knum;
import cn.com.utt.common.proto.ServiceZone.Wpa;
import cn.com.utt.common.proto.ServiceZone.Wpapsk;
import cn.com.utt.common.protorpc.RPCClient;
import cn.com.utt.common.util.DesUtil;
import cn.com.utt.common.util.LocaleMessageSourceUtil;
import cn.com.utt.common.util.Token;
import cn.com.utt.common.util.MqttDeviceClientConfig;
import cn.com.utt.common.util.Tips;
import cn.com.utt.common.util.UttTool;
import cn.com.utt.common.vo.RestResult;
import cn.com.utt.common.vo.SearchParameter;
import cn.com.utt.common.vo.TableInput;
import cn.com.utt.common.vo.TableOutput;
import cn.com.utt.common.zk.APIDiscovery;
import cn.com.utt.common.zk.HttpDNSDiscovery;
import cn.com.utt.unms.mapper.RfMapper;
import cn.com.utt.unms.mapper.DeviceMapper;
import cn.com.utt.unms.mapper.EventLogMapper;
import cn.com.utt.unms.mapper.NetworkMapper;
import cn.com.utt.unms.mapper.SsidMapper;
import cn.com.utt.unms.mapper.GroupNetworkMapper;
import cn.com.utt.unms.mapper.WirelessMapper;
import cn.com.utt.unms.pojo.Rf;
import cn.com.utt.unms.pojo.Device;
import cn.com.utt.unms.pojo.Network;
import cn.com.utt.unms.pojo.Ssid;
import cn.com.utt.unms.pojo.Wireless;
import cn.com.utt.unms.service.DeviceService;
import cn.com.utt.unms.service.UserRecordService;
import cn.com.utt.unms.utils.GraphUtils;
import cn.com.utt.unms.vo.DeviceInfo;
import cn.com.utt.unms.vo.GraphLastParam;
import cn.com.utt.unms.vo.GraphLastResp;
import cn.com.utt.unms.vo.GraphQueryIntegerValue;
import cn.com.utt.unms.vo.GraphQueryParam;
import cn.com.utt.unms.vo.GraphQueryResponse;
import cn.com.utt.unms.vo.GraphQueryValue;
import cn.com.utt.unms.vo.SoftVersion;

@Service("deviceService")
public class DeviceServiceImpl implements DeviceService {
	
	@Autowired
    private LocaleMessageSourceUtil messageSourceUtil;
	
	@Autowired
	private DeviceMapper deviceMapper;

	@Autowired
	private WirelessMapper wirelessMapper;

	@Autowired
	private GroupNetworkMapper groupNetworkMapper;

	@Autowired
	private NetworkMapper networkMapper;

	@Autowired
	private RfMapper rfMapper;
	@Autowired
	private SsidMapper ssidMapper;
	@Autowired
	private RPCClient rpcClient;

	@Autowired
	private APIDiscovery apiDiscovery;

	@Autowired
	private UserRecordService userRecordService;

	@Autowired
	private HttpDNSDiscovery httpDNSDiscoery;

	@Autowired
	private EventLogMapper eventLogMapper;
	
	@Override
	public Device queryDeviceBySn(String sn) {
		return deviceMapper.queryDeviceBySn(sn);
	}
	
	@Override
	@doLog(description = Tips.LogModifyDevice, key = { "#device.name" })
	public RestResult update(Device device) {
		RestResult result=new RestResult();
		deviceMapper.update(device);
		return result;
	}

	@Override
	public TableOutput<DeviceInfo> queryByCondition(TableInput input, long rootGroupId, boolean isVn) {
		// 查询当前用户所管理的组的
		List<Long> networkIds = new ArrayList<>();
		Map<Long, Network> networkMap = new HashMap<>();
		List<Network> networks = null;
		boolean flag = false;
		// 1、input查询条件里是否有network这个参数
		if (input.getSearch() != null && input.getSearch().size() > 0) {
			Iterator<SearchParameter> iterator = input.getSearch().iterator();
			while (iterator.hasNext()) {
				SearchParameter search = iterator.next();
				if ("network_id".equals(search.getColumn())) {
					// 如果有以参数中的network来查询设备，如果没有则以组下的所有局点来查询
					networkIds.add(Long.parseLong(search.getValue()));
					flag = true;
					iterator.remove();
					break;
				}
				if ("group_id".equals(search.getColumn())) {
					long groupId = Long.parseLong(search.getValue());
					List<Long> ids = groupNetworkMapper.queryByGroupId(groupId);
					networkIds.addAll(ids);
					flag = true;
					iterator.remove();
					break;
				}
			}
		}
		if (!flag) {
			List<Long> ids = groupNetworkMapper.queryByGroupId(rootGroupId);
			networkIds.addAll(ids);
		}
		if (networkIds.size() > 0) {
			networks = networkMapper.queryByIds(networkIds);
			if (networks != null) {
				for (Network network : networks) {
					networkMap.put(network.getId(), network);
				}
			}
		}
		
		Map<String, Object> conditions = new HashMap<>();
		conditions.put("networkIds", networkIds);
		conditions.put("searchs", input.getSearch());
		
		if (input.getOrder() != null) {
			conditions.put("orderColumn", input.getOrder().getColumn());
			conditions.put("orderDirection", input.getOrder().getDir());
		}else{
			conditions.put("orderColumn", "id");
			conditions.put("orderDirection", "asc");
		}
		conditions.put("start", input.getStart());
		conditions.put("rows", input.getRows());
		int total = 0;
		List<Device> devices = new ArrayList<>();
		if (networkIds.size() > 0) {
			total = deviceMapper.countByCondition(conditions);
			devices = deviceMapper.queryByCondition(conditions);
		}
		
		// TODO查询设备的实时数据
		TableOutput<DeviceInfo> output = new TableOutput<>();
		output.setTotal(total);
		output.setRows(input.getRows());
		output.setStart(input.getStart());
		
		Map<String, DeviceInfo> infos = new HashMap<>();
		List<GraphLastParam> onlineparams = new ArrayList<>();
		
		for (Device device : devices) {
			DeviceInfo info = new DeviceInfo();
			info.convert(device, isVn);
			Network network = networkMap.get(device.getNetworkId());
			if (network != null) {
				info.setGroup(network.getName());
				info.setNetworkId(network.getId());
			}
			if (device.getRfId() != null && device.getRfId() > 0) {
				Rf rf = rfMapper.findById(device.getRfId());
				info.setRfConfig(rf.getName());
				info.setRfConfigId(device.getRfId());
			} else {
				info.setRfConfig("-");
			}
			
			
			if (device.getType().equals("1")) {
				info.setType("router");
				info.setSystemMode("-");
				info.setIsWirelessExtend((byte)1);
			} else if (device.getType().equals("1.1")) {
				info.setType("router");
				info.setSystemMode("-");
				info.setIsWirelessExtend((byte)0);
			} else if (device.getType().equals("2")) {
				info.setType("AP");
				// 0 瘦 1 胖
				if (device.getSystemMode() == 0) {
					info.setSystemMode("FIT AP");
				} else if (device.getSystemMode() == 1) {
					info.setSystemMode("FAT AP");
				} else {
					info.setSystemMode("-");
				}
			} else {
				info.setType("-");
				info.setSystemMode("-");
			}
			
			
			List<Wireless> wirelesses = wirelessMapper.queryByNetworkId(device.getNetworkId());
			if (wirelesses != null && wirelesses.size() > 0) {
				String wStr = "";
				String ssid24G = "";
				String ssid5G = "";
				for (Wireless wireless : wirelesses) {
					wStr += wireless.getName() + ",";
					Ssid ssid = ssidMapper.querySsidsByWireless(wireless.getId());
					switch (ssid.getFreqChannel()) {
					case 0:
						ssid24G += ssid.getName() + ",";
						ssid5G += ssid.getName() + ",";
						break;
					case 1:
						ssid24G += ssid.getName() + ",";
						break;
					case 2:
						ssid5G += ssid.getName() + ",";
						break;
					default:
						break;
					}
				}
				if (wStr != "") {
					wStr = wStr.substring(0, wStr.length() - 1);
				}
				if (ssid24G != "") {
					ssid24G = ssid24G.substring(0, ssid24G.length() - 1);
				}
				if (ssid5G != "") {
					ssid5G = ssid5G.substring(0, ssid5G.length() - 1);
				}

				info.setWireless(wStr);
				info.setSsid24G(ssid24G);
				info.setSsid5G(ssid5G);
			}
			info.setRadio(device.getRadio());// radio为空，默认不支持2.4G、5G
			infos.put(info.getSn(), info);
			// 查询在线状态参数
			if (device.getStatus() == 1) {// 设备在线
				long day = 0;
				long hour = 0;
				long min = 0;
				long sec = 0;
				long time = (System.currentTimeMillis() -device.getOnlineTime().getTime()) / 1000;
				day = time / (24 * 60 * 60);
				hour = (time / (60 * 60) - day * 24);
				min = ((time / (60)) - day * 24 * 60 - hour * 60);
				sec = (time - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
				info.setUptime(day + " "+messageSourceUtil.getMessage(Tips.Day)+" " + hour + " "+messageSourceUtil.getMessage(Tips.Hour)+" " + min + " "+messageSourceUtil.getMessage(Tips.Minute)+" " + sec + " " + messageSourceUtil.getMessage(Tips.Second));
				GraphLastParam outBytes = new GraphLastParam();
				outBytes.setCounter("net.out.bytes");
				outBytes.setEndpoint(info.getSn());
				onlineparams.add(outBytes);
				GraphLastParam inBytes = new GraphLastParam();
				inBytes.setCounter("net.in.bytes");
				inBytes.setEndpoint(info.getSn());
				onlineparams.add(inBytes);
				GraphLastParam apCount = new GraphLastParam();
				apCount.setCounter("ap.count");
				apCount.setEndpoint(info.getSn());
				onlineparams.add(apCount);

			}else{
				info.setUptime("--");
			}
			
		}
		// 查询设备的在线状况
		Client client = new Client();
		String result = client.doPostWithJson("http://" + apiDiscovery.discover() + "/api/v1/graph/lastrawpoint",
				JSON.toJSONString(onlineparams));
		if (result != null && result.length() > 0) {
			List<GraphLastResp> resps = JSON.parseArray(result, GraphLastResp.class);
			if (resps != null) {
				for (GraphLastResp resp : resps) {
					DeviceInfo info = infos.get(resp.getEndpoint());
					if (info == null || info.getStatus() != 1) {
						continue;
					}
					switch (resp.getCounter()) {
					case "net.out.bytes": // 上传流量
						info.setSent(UttTool.getPrintSize(resp.getValue().getValue().floatValue()));
						break;
					case "net.in.bytes": // 下载流量
						info.setRecv(UttTool.getPrintSize(resp.getValue().getValue().floatValue()));
						break;
					case "ap.count": // 下载流量
						info.setAps(resp.getValue().getValue().intValue());
						break;
					default:
						break;
					}
				}

			}
		}
		List<DeviceInfo> deviceList = new ArrayList<>(infos.values());
		Collections.sort(deviceList, new Comparator<DeviceInfo>() {
			public int compare(DeviceInfo o1, DeviceInfo o2) {
				if (o1.getId() > o2.getId()){
					return 1;
				}else{
					return -1;
				}
			}
		});
		output.setList(deviceList);
		return output;
	}

	@Override
	@doLog(description = Tips.LogImportDevice, key = { "#device.sn" })
	public RestResult save(Device device) {
		RestResult result=new RestResult();
		deviceMapper.save(device);
		syncDeviceStatusAndReUp(new ArrayList<String>() {{add(device.getSn());}},"http://" + httpDNSDiscoery.discover() + "/device/bind?",1,2);
		result.put("deviceId", device.getId());
		return result;
	}
	
	@Override
	public void batchSave(Map<String, Device> devices) {
		if(!devices.values().isEmpty()){
			deviceMapper.batchSave(devices.values());
			
			if (TransactionSynchronizationManager.isActualTransactionActive()) {
	            TransactionSynchronizationManager
	                    .registerSynchronization(new TransactionSynchronizationAdapter() {
	                        @Override
	                        public void afterCommit() {
	                            // 事务提交后执行回调
	                        		syncDeviceStatusAndReUp(devices.keySet(),"http://" + httpDNSDiscoery.discover() + "/device/bind?",1,2);
	                        }
	                    });
	        } else {
	            // 事务提交后执行回调
	        		syncDeviceStatusAndReUp(devices.keySet(),"http://" + httpDNSDiscoery.discover() + "/device/bind?",1,2);
	        }
			
		}
	}
	
	private void syncDeviceStatusAndReUp(Collection<String> sns,String url,int connect, int delay){
		if (sns.size() > 0){
			for (String sn : sns) {
				url = url + "sns=" + sn + "&";
				reUp(sn, connect, delay);
			}
			url = url.substring(0, url.length() - 1);
			Client client = new Client();
			String result = client.doGetWithJson(url);
			System.out.println("client.doGet result:");
			System.out.println(result);
		}
		
	}

	@Override
	public Device queryDeviceById(long deviceid) {
		return deviceMapper.queryDeviceById(deviceid);
	}

	@Override
	public List<Device> queryDeviceByIds(List<Long> deviceIds) {
		return deviceMapper.queryDevicesByIds(deviceIds);
	}

	@Override
	public List<Device> queryChildrenDevicesByGroupId(long groupId) {
		// 查询分组下面所有的局点
		List<Long> networkIds = groupNetworkMapper.queryByGroupId(groupId);
		List<Device> devices = queryDevicesByNetworkIds(networkIds);
		return devices;
	}

	@Override
	public List<Device> queryDevicesByNetworkIds(List<Long> networkIds) {
		List<Device> devices = null;
		if (networkIds != null && networkIds.size() > 0) {
			devices = deviceMapper.queryDevicesByNetworkIds(networkIds);
		} else {
			devices = new ArrayList<>();
		}
		return devices;
	}

	@Override
	public Object queryHistoryByNetwork(long userId, long networkId, long start, long end, byte type, byte shape, int range) {
		Date d = new Date();
		long endTime = d.getTime();
		long startTime;
		Calendar calendar = Calendar.getInstance();
		switch (range) {
		case 2: // 一月
			calendar.setTime(d);
			calendar.add(Calendar.MONTH, -1);
			Date m = calendar.getTime();
			startTime = m.getTime();
			break;
		case 1: // 一周
			calendar.setTime(d);
			calendar.add(Calendar.WEEK_OF_YEAR, -1);
			Date w = calendar.getTime();
			startTime = w.getTime();
			endTime=d.getTime()-60*1000*10;
			break;
		case 0: // 一天
			calendar.setTime(d);
			calendar.add(Calendar.DAY_OF_WEEK, -1);
			Date day = calendar.getTime();
			startTime = day.getTime();
			endTime=d.getTime()-60*1000;
			break;
		default: // 一天
			calendar.setTime(d);
			calendar.add(Calendar.DAY_OF_WEEK, -1);
			startTime = calendar.getTime().getTime();
			endTime=d.getTime()-60*1000;
			break;
		}

		Map<String, List<GraphQueryIntegerValue>> datas = null;
		Map<String, Integer> pie = null;
		List<Device> devices = queryDevicesByNetworkIds(new ArrayList<Long>() {{add(networkId);}});
		if (shape == 1) {
			int onlines = 0;
			int offlines = 0;
			for (Device device : devices) {
					if (device.getStatus() == 1) {
						onlines++;
					} else {
						offlines++;
					}
			}
			pie = new HashMap<>();
			pie.put("onlines", onlines);
			pie.put("offlines", offlines);
			return pie;
		} else if (shape == 2) {
			int i = 0;
			int j = 0;
			for (Device device : devices) {
				if (device.getType().equals((byte) 1)) {//路由
					i++;
				}
				if (device.getType().equals((byte) 2)) {//ap
					j++;
				}
			}
			String[] ap_sns = new String[j];
			String[] r_sns = new String[i];
			i = 0;
			j = 0;
			for (Device device : devices) {
				if (device.getType().equals((byte) 1)) {
					r_sns[i] = device.getSn();
					i++;
				}
				if (device.getType().equals((byte) 2)) {
					ap_sns[j] = device.getSn();
					j++;
				}
			}
			GraphQueryParam params = new GraphQueryParam();
			params.setConsolFun("MAX");
			params.setStartTime(startTime/1000);
			params.setEndTime(endTime/1000);
			params.setCounters(new String[] { "system.uptime" });
			params.setStep(60);
			params.setHostNames(ap_sns);
			GraphQueryParam params1 = new GraphQueryParam();
			params1.setConsolFun("MAX");
			params1.setStartTime(startTime/1000);
			params1.setEndTime(endTime/1000);
			params1.setCounters(new String[] { "system.uptime" });
			params1.setStep(60);
			params1.setHostNames(r_sns);
			List<GraphQueryResponse> ap_series = client_doPost(params);
			List<GraphQueryResponse> r_series = client_doPost(params1);
			boolean hasData = false;
			if (ap_series != null) {
				for (GraphQueryResponse ap_serie : ap_series) {
					if (ap_serie.getValues().size() < 1) {
						// 没有数据的设备跳过
						continue;
					}
					hasData = true;
				}
			}
			if (r_series != null) {
				for (GraphQueryResponse r_serie : r_series) {
					if (r_serie.getValues().size() < 1) {
						// 没有数据的设备跳过
						continue;
					}
					hasData = true;
				}
			}
			List<GraphQueryIntegerValue> allValues = new ArrayList<>();
			List<GraphQueryIntegerValue> apValues = new ArrayList<>();
			List<GraphQueryIntegerValue> rValues = new ArrayList<>();
			
			Map<Long, Integer> allValuesM = new TreeMap<Long, Integer>(
	                new Comparator<Long>() {
	                    public int compare(Long obj1, Long obj2) {
	                        // 降序排序
	                        return obj1.compareTo(obj2);
	                    }
	                });
			Map<Long, Integer> apValuesM = new TreeMap<Long, Integer>(
	                new Comparator<Long>() {
	                    public int compare(Long obj1, Long obj2) {
	                        // 降序排序
	                        return obj1.compareTo(obj2);
	                    }
	                });Map<Long, Integer> rValuesM = new TreeMap<Long, Integer>(
	    	                new Comparator<Long>() {
	    	                    public int compare(Long obj1, Long obj2) {
	    	                        // 降序排序
	    	                        return obj1.compareTo(obj2);
	    	                    }
	    	                });
			if (hasData) {
				for (GraphQueryResponse ap_serie : ap_series) {
					List<GraphQueryValue> ap_values = ap_serie.getValues();
					if (ap_values.size() < 1) {
						continue;
					}
					//根据绑定时间筛选出设备数据
					for (int k = 0; k < devices.size(); k++) {
						if(ap_serie.getEndpoint().equals(devices.get(k).getSn())){
						    for (int k2 = 0; k2 < ap_values.size(); k2++) {
						    		ap_values.get(k2).setTimestamp(ap_values.get(k2).getTimestamp() * 1000);
						    		ap_values.get(k2).setValue(ap_values.get(k2).getValue() == null ? 0.0 : 1.0);
								if(devices.get(k).getBindTime().getTime()<=ap_values.get(k2).getTimestamp()){
									Double value = ap_values.get(k2).getValue();
									Integer count = apValuesM.get(ap_values.get(k2).getTimestamp());
									Integer countAll = allValuesM.get(ap_values.get(k2).getTimestamp());
									if (value == 1.0){
										apValuesM.put(ap_values.get(k2).getTimestamp(), count == null?1:count+1);
										allValuesM.put(ap_values.get(k2).getTimestamp(), countAll == null?1:countAll+1);
									}
								}
							}
						}
					}
				}
				for (GraphQueryResponse r_serie : r_series) {
					List<GraphQueryValue> r_values = r_serie.getValues();
					if (r_values.size() < 1) {
						continue;
					}
					//根据绑定时间筛选出设备数据
					for (int k = 0; k < devices.size(); k++) {
						if(r_serie.getEndpoint().equals(devices.get(k).getSn()))
							for (int k2 = 0; k2 < r_values.size(); k2++) {
								r_values.get(k2).setTimestamp(r_values.get(k2).getTimestamp() * 1000);
								r_values.get(k2).setValue(r_values.get(k2).getValue() == null ? 0.0 : 1.0);
								if(devices.get(k).getBindTime().getTime()<=r_values.get(k2).getTimestamp()){
									Double value = r_values.get(k2).getValue();
									Integer count = rValuesM.get(r_values.get(k2).getTimestamp());
									Integer countAll = allValuesM.get(r_values.get(k2).getTimestamp());
									if(value == 1.0){
										rValuesM.put(r_values.get(k2).getTimestamp(), count == null?1:count+1);
										allValuesM.put(r_values.get(k2).getTimestamp(), countAll == null?1:countAll+1);
									}
								}
							}
						}
					}
				}
				for(Map.Entry<Long, Integer> entry : allValuesM.entrySet()){
					Long time = entry.getKey();
					Integer mapValue = entry.getValue();
					GraphQueryIntegerValue gqiv = new GraphQueryIntegerValue();
					gqiv.setTimestamp(time);
					gqiv.setValue(mapValue);
					allValues.add(gqiv);
				}
				
				for(Map.Entry<Long, Integer> entry : apValuesM.entrySet()){
					Long time = entry.getKey();
					Integer mapValue = entry.getValue();
					GraphQueryIntegerValue gqiv = new GraphQueryIntegerValue();
					gqiv.setTimestamp(time);
					gqiv.setValue(mapValue);
					apValues.add(gqiv);
				}
				for(Map.Entry<Long, Integer> entry : rValuesM.entrySet()){
					Long time = entry.getKey();
					Integer mapValue = entry.getValue();
					GraphQueryIntegerValue gqiv = new GraphQueryIntegerValue();
					gqiv.setTimestamp(time);
					gqiv.setValue(mapValue);
					rValues.add(gqiv);
				}
				
				datas = new HashMap<>();
				datas.put("apValues", apValues);
				datas.put("rValues", rValues);
				datas.put("allValues", allValues);
			}
		return datas;
	}

	public List<GraphQueryResponse> client_doPost(GraphQueryParam params) {
		// 调用falcon-plus的api接口查询历史数据
		Client client = new Client();
		String result = "[]";
		if (params.getHostNames() != null && params.getHostNames().length > 0) {
			result = client.doPostWithJson("http://" + apiDiscovery.discover() + "/api/v1/graph/history",
					JSON.toJSONString(params));
		}
		List<GraphQueryResponse> series = null;
		if (result != null && result.length() > 0) {
			// 合并数据，按counter合并
			series = JSON.parseArray(result, GraphQueryResponse.class);
			return series;
		}
		return null;
	}

	@Override
	public Map<String, Object> remoteWebStatus(String sn,String host) {
		Map<String, Object> result = new HashMap<String, Object>();
		// 2、根据序列号查找主题
		String topic = MqttDeviceClientConfig.router(sn);
		// 3、发送Get命令查询远程状态
		Get get = new Get();
		get.setId(Token.getToken());
		get.setReplyTo(Token.getToken());
		String[] names = new String[] { "ssh.portforward" };
		get.setData(names);
		GetResp getResp = null;
		try {
			Message resp = rpcClient.callWithTimeout(topic, get, 5);
			if (resp != null) {
				getResp = (GetResp) resp;
			}
		} catch (Exception e) {
			System.out.println("exception");
			e.printStackTrace();
			result.put("errorCode", 2);
			result.put("errorMsg", messageSourceUtil.getMessage(Tips.OperationFailed));
			return result;
		}
		if (getResp != null && (getResp.getError() == null)) {
			String[] portforwards = null;
			// if (getResp.getData() instanceof Map) {
			JSONObject json = (JSONObject) getResp.getData();
			if (json != null && json.get("values") != null) {
				JSONObject js = JSONObject.parseObject(json.get("values").toString());
				for (Map.Entry<String, Object> status : js.entrySet()) {
					portforwards = status.getValue().toString().split(":");
					if (portforwards !=null){
						if(portforwards.length == 2 && "80".equals(portforwards[0])){
							result.put("errorCode", 0);
							result.put("errorMsg", "success");
							result.put("portforward", "http://" + portforwards[1] + "."+host);
							return result;
						}else if(portforwards.length == 1 && portforwards[0].length() > 0){
							result.put("errorCode", 3);
							result.put("errorMsg", messageSourceUtil.getMessage(Tips.RemoteConnectFail));
							result.put("webport", portforwards[0]);
							return result;
						}
					}
				}
			}
			// }
		}
		return null;
	}

	@Override
	public Map<String, Object> remoteConnect(String sn,String webport,String host) {
		Map<String, Object> result = new HashMap<String, Object>();
		// 2、根据序列号查找主题
		String topic = MqttDeviceClientConfig.router(sn);
		// 3、发送远程控制命令，让设备建立远程连接
		Command command = new Command();
		command.setId(Token.getToken());
		command.setReplyTo("ap/" + sn);
		command.setTimeout(30);
		if (webport == null || webport.length() == 0){
			webport = "80";
		}
		String[] cmds = new String[] {
				"autossh -M 0 -i /etc/dropbear/id_rsa -f -N -T -R 0:localhost:"+webport+"  -p 60022 tunnel@"+host};//,
//				"autossh -M 0 -i /etc/dropbear/id_rsa -f -N -T -R 0:localhost:60023 -p 60022 tunnel@"+host};
		command.setCommands(cmds);
		try {
			rpcClient.send(topic, command);
		} catch (Exception e) {
			result.put("errcode", 2);
			result.put("msg", messageSourceUtil.getMessage(Tips.OperationFailed));
			return result;
		}
		return null;
	}

	@Override
	public RestResult isRightFormate(Device device) {
		RestResult result = new RestResult();
		if(device.getImportType() == 2){
			return result;
		}
		if (device.getName().length() > 64) {
			result.setErrorCode(-1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn1).replaceAll("#", device.getSn()));
			return result;
		}
		int temp = device.getName().indexOf(" ");
		if (temp != -1) {
			result.setErrorCode(5);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn2));
			return result;
		}
		device.setSn(device.getSn().trim());
		if ("".equals(device.getSn())) {
			result.setErrorCode(6);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn3));
			return result;
		}
//		if (device.getSn().length() != 8 && device.getSn().length() != 10) {
//			result.setErrorCode(-1);
//			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn4).replaceAll("#", device.getSn()));
//			return result;
//		}
//		if (!(UttTool.isNumeric(device.getSn()))) {
//			result.setErrorCode(-1);
//			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn5).replaceAll("#", device.getSn()));
//			return result;
//		}
		device.setCode(device.getCode().trim());
		if ("".equals(device.getCode())) {
			result.setErrorCode(-1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn6).replaceAll("#", device.getSn()));
			return result;
		}
		if (device.getCode().length() != 6) {
			result.setErrorCode(-1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn7).replaceAll("#", device.getSn()));
			return result;
		}
		if (device.getSn().startsWith("C1200")){
			DesUtil desUtil1 = new DesUtil(device.getSn().substring(5),1);
			DesUtil desUtil2 = new DesUtil(device.getSn().substring(5),2);
			String mistr1 = desUtil1.getEncString(device.getSn().substring(5),1);
			String mistr2 = desUtil2.getEncString(device.getSn().substring(5),2);
			if (!(mistr1.startsWith(device.getCode())) && !(mistr2.startsWith(device.getCode()))) {
				result.setErrorCode(11);
				result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn8).replaceAll("#", device.getSn()));
				return result;
			}
			device.setSn(device.getSn().substring(5));
		}else{
			DesUtil desUtil1 = new DesUtil(device.getSn(),1);
			DesUtil desUtil2 = new DesUtil(device.getSn(),2);
			String mistr1 = desUtil1.getEncString(device.getSn(),1);
			String mistr2 = desUtil2.getEncString(device.getSn(),2);
			if (!(mistr1.startsWith(device.getCode())) && !(mistr2.startsWith(device.getCode()))) {
				result.setErrorCode(11);
				result.setErrorMsg(messageSourceUtil.getMessage(Tips.FailSn8).replaceAll("#", device.getSn()));
				return result;
			}
		}
		return result;
	}

	@Override
	@doLog(description = Tips.LogUnboundDevice, key = { "" })
	public RestResult unbind(List<Device> devices) {
		RestResult result = new RestResult();
		deviceMapper.unbind(devices);
		List<String> sn = new ArrayList<>();
		for (Device device : devices) {
			sn.add(device.getSn());
		}
		syncDeviceStatusAndReUp(sn,"http://" + httpDNSDiscoery.discover() + "/device/unbind?",1,2);
		eventLogMapper.delete(sn);// 清除告警信息
		userRecordService.delete(sn);// 清除用户信息
		return result;
	}
	
	@Override
	public void switchFast(List<Device> devices, byte isFast) {
		for (Device device : devices) {
			String topic = MqttDeviceClientConfig.router(device.getSn());
			Set set = new Set();
			set.setId(Token.getToken());
			set.setReplyTo(Token.getToken());
			set.setCommit(false);
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("isFast", isFast);
			set.setData(JSON.toJSON(params));
			try {
				rpcClient.send(topic, set);
			} catch (Exception e) {
				System.out.println("exception");
				e.printStackTrace();
				continue;
			}
			device.setIsFast(isFast);
			deviceMapper.update(device);
		}
	}

	@Override
	public RestResult updateDeviceWireless(List<Device> devices, List<Wireless> wirelesses, boolean... flag) {
		RestResult result = new RestResult();
		Object data = getServiceZoneData(wirelesses);
		for (Device device : devices) {
			long version = device.getVersion() + 1;
			device.setVersion(version);
			deviceMapper.update(device);
			if (device.getStatus() == 1 && device.getType().equals("2")) {// 设备在线
				// 下发配置
				cn.com.utt.common.message.Set msg = new cn.com.utt.common.message.Set();
				String topic = MqttDeviceClientConfig.router(device.getSn());
				String setId = Token.getToken();
				msg.setId(setId);
				msg.setReplyTo(Token.getToken());
				msg.setCommit(false);
				Map<String, Object> params = new HashMap<String, Object>();
				params.put("ServiceZone", data);
				params.put("version", version);
				msg.setData(JSON.toJSON(params));
				
				if (device.getSystemMode() == 0) {
					try {
						if (flag.length > 0 && flag[0]) {
							rpcClient.callWithTimeout(topic, msg, 5);
						} else {
							rpcClient.send(topic, msg);
						}
					} catch (RPCException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
		
		String url = "http://" + httpDNSDiscoery.discover() + "/device/bind?";
		List<String> sns = devices.stream().map(Device::getSn).collect(Collectors.toList());
		for (String sn : sns) {
			url = url + "sns=" + sn + "&";
		}
		url = url.substring(0, url.length() - 1);
		final String url_ = url;
		Client client = new Client();
		if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager
                    .registerSynchronization(new TransactionSynchronizationAdapter() {
                        @Override
                        public void afterCommit() {
                            // 事务提交后执行回调
                        		client.doGetWithJson(url_);
                        }
                    });
        } else {
            // 事务提交后执行回调
			client.doGetWithJson(url);
        }
		
		return result;
	}

	@Override
	public RestResult writeFileToDisk(MultipartFile file, String path) {
		RestResult result = new RestResult();
		if (file.isEmpty()) {
			result.setErrorCode(-1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.FileDoesNotExist));
			return result;
		}
		String originalFilename = file.getOriginalFilename();
		String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
		String filename = path + "/" + String.valueOf(System.currentTimeMillis()) + "." + fileType;
		try {
			OutputStream os = new FileOutputStream(filename);
			InputStream is = file.getInputStream();
			int temp;
			while ((temp = is.read()) != (-1)) {
				os.write(temp);
			}
			os.flush();
			os.close();
			is.close();
		} catch (Exception e) {
			result.setErrorCode(-1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.Error));
			return result;
		}
		result.setErrorMsg(filename);
		return result;
	}
	
	@Override
	@Transactional
	@doLog(description = Tips.LogBatchImportDevice, key = { "" })
	public RestResult readExcelAndBindDevice(File file, long networkId, long rootGroupId, int type) {
		RestResult result = new RestResult();
		String fileName = file.getName();
		String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
		Workbook xssfWorkbook = null;
		InputStream stream = null;
		try {
			stream = new FileInputStream(file);
			if (fileType.equals("xls")) {
				xssfWorkbook = new HSSFWorkbook(stream);
			} else if (fileType.equals("xlsx")) {
				xssfWorkbook = new XSSFWorkbook(stream);
			} else {
				if (stream != null) {
					stream.close();
				}
				result.setErrorCode(-1);
				result.setErrorMsg(messageSourceUtil.getMessage(Tips.IncorrectExcelFormat));
				return result;
			}
		} catch (Exception e) {
			result.setErrorCode(-1);
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.Error));
			return result;
		}
		// Read the Sheet
		Sheet Sheet = xssfWorkbook.getSheetAt(0);
		
		List<Long> networkIds = groupNetworkMapper.queryByGroupId(rootGroupId);
		String errorMsg = "";
		int errorCode = 0;
		boolean unsafe = true;
		boolean snNull = false;
		Map<String, Device> savedDevice = new HashMap<>();
		
		for (int rowNum = 1; rowNum <= Sheet.getLastRowNum(); rowNum++) {
			Row row = Sheet.getRow(rowNum);
			if (row != null) {
				// 获取每一行
				int max = row.getLastCellNum();
				if(type == 1){
					if (max == 0 || (getValue(row.getCell(0)).trim().equals("")
							&& getValue(row.getCell(1)).trim().equals("") && getValue(row.getCell(2)).trim().equals(""))) {
						continue;
					}
					if (max > 3) {
						result.setErrorCode(-1);
						result.setErrorMsg(messageSourceUtil.getMessage(Tips.IncorrectExcelFormat));
						return result;
					}
				}else{
					continue;
				}
				Device device = new Device();
				Device temp = null;
				device.setName(getValue(row.getCell(0)).trim());
				device.setNetworkId(networkId);
				if(type == 1){
					device.setSn(getValue(row.getCell(1)).trim());
					device.setCode(getValue(row.getCell(2)).trim());
					device.setImportType((byte)1);
					temp = queryDeviceBySn(device.getSn());
				}
				if (temp == null) {
					result = isRightFormate(device);
					if (result.getErrorCode() != 0) {
						if (result.getErrorCode() == 5) {
							if (unsafe) {
								errorCode = 1;
								errorMsg += result.getErrorMsg() + "</br>";
								unsafe = false;
							}
						} else if (result.getErrorCode() == 6) {
							if (!snNull) {
								errorCode = 1;
								errorMsg += result.getErrorMsg() + "</br>";
								snNull = true;
							}
						} else {
							errorCode = 1;
							errorMsg += result.getErrorMsg() + "</br>";
						}
					}else{
						savedDevice.put(device.getSn(), device);
					}
				}else{
					if (!networkIds.contains(temp.getNetworkId())){
						errorCode = 1;
						errorMsg += messageSourceUtil.getMessage(Tips.FailSn9).replaceAll("#", device.getSn()) + "</br>";
						continue;
					}
				}
				
			}
		}
		batchSave(savedDevice);
		
		if (errorMsg == "") {
			errorMsg = messageSourceUtil.getMessage(Tips.OperationSucceed);
		}
		result.setErrorCode(errorCode);
		result.setErrorMsg(errorMsg);
		return result;
	}

	private String getValue(Cell cell) {
		if (cell == null) {
			return "";
		}
		cell.setCellType(Cell.CELL_TYPE_STRING);
		return cell.getStringCellValue().trim();
	}

	@Override
	public boolean hasRight(Device device, long userGroupId) {
		List<Long> networkIds = groupNetworkMapper.queryByGroupId(userGroupId);
		if (networkIds.size() == 0) {
			return false;
		}
		if(!networkIds.contains(device.getNetworkId())){
			return false;
		}
		return true;
	}

	@Override
	public boolean hasRights(List<Device> devices, long userGroupId) {
		
		List<Long> networkIds = groupNetworkMapper.queryByGroupId(userGroupId);
		if (networkIds.size() == 0) {
			return false;
		}
		for (Device device : devices) {
			if(!networkIds.contains(device.getNetworkId())){
				return false;
			}
		}
		return true;
	}
	
	public Object getServiceZoneData(List<Wireless> wirelesses) {
		if (wirelesses == null || wirelesses.size() == 0) {
			return "";
		}
		List<ServiceZone> serviceZones = new ArrayList<>();
		for (Wireless wireless : wirelesses) {
			Ssid ssid = ssidMapper.querySsidsByWireless(wireless.getId());
			if (ssid != null) {
				int radio = ssid.getFreqChannel();
				ServiceZone G24 = null;
				ServiceZone G5 = null;
				switch (radio) {
				case 0:
					G24 = createServiceZone(wireless, ssid, 1);
					G5 = createServiceZone(wireless, ssid, 2);
					serviceZones.add(G24);
					serviceZones.add(G5);
					break;
				case 1:
					G24 = createServiceZone(wireless, ssid, 1);
					serviceZones.add(G24);
					break;
				case 2:
					G5 = createServiceZone(wireless, ssid, 2);
					serviceZones.add(G5);
					break;
				}
			}
		}
		return JSON.toJSON(serviceZones);
	}

	public ServiceZone createServiceZone(Wireless wireless, Ssid ssid, int radio) {
		ServiceZone sz = new ServiceZone();
		sz.setEncode(ssid.getEncode());
		sz.setRadio(radio);// 2.4G 5G
		sz.setRfIndex(1);
		sz.setSzName(wireless.getName());
		sz.setAuthMode(ssid.getSecType());
		sz.setSsidName(ssid.getName());
		sz.setVlanType(ssid.getAutoUpdate()); // 是否自动下发
		sz.setSsidHide(ssid.getHide());
		sz.setStaIsolation(ssid.getClientIsolation());
		sz.setVlan(ssid.getVid());
		RateLimit rateLimit = sz.new RateLimit();
		rateLimit.setDownRate(ssid.getRxrate());
		rateLimit.setUpRate(ssid.getTxrate());
		rateLimit.setMode(ssid.getMode());
		sz.setRateLimit(rateLimit);
		Wep wep = sz.new Wep();
		Wpa wpa = sz.new Wpa();
		Wpapsk wpapsk = sz.new Wpapsk();
		Knum knum1 = wep.new Knum();
		Knum knum2 = wep.new Knum();
		Knum knum3 = wep.new Knum();
		Knum knum4 = wep.new Knum();
		switch (ssid.getSecType()) {
		case 1:
			switch (ssid.getWepKeyIndex()) {
			case 1:
				knum1.setPasswd(ssid.getWepKeyPassphrase());
				knum1.setType(ssid.getWepKeyFormat());
				knum1.setKfmt(ssid.getWepEncryptionLevel());
				knum1.setKeySate(ssid.getWepEncryptionLevel() != 0 ? "Yes" : "No");
				knum1.setAuthMethod(ssid.getWepEncryptionMode());
				knum2.setKeySate("No");
				knum3.setKeySate("No");
				knum4.setKeySate("No");
				break;
			case 2:
				knum2.setPasswd(ssid.getWepKeyPassphrase());
				knum2.setType(ssid.getWepKeyFormat());
				knum2.setKfmt(ssid.getWepEncryptionLevel());
				knum2.setKeySate(ssid.getWepEncryptionLevel() != 0 ? "Yes" : "No");
				knum2.setAuthMethod(ssid.getWepEncryptionMode());
				knum1.setKeySate("No");
				knum3.setKeySate("No");
				knum4.setKeySate("No");
				break;
			case 3:
				knum3.setPasswd(ssid.getWepKeyPassphrase());
				knum3.setType(ssid.getWepKeyFormat());
				knum3.setKfmt(ssid.getWepEncryptionLevel());
				knum3.setKeySate(ssid.getWepEncryptionLevel() != 0 ? "Yes" : "No");
				knum3.setAuthMethod(ssid.getWepEncryptionMode());
				knum1.setKeySate("No");
				knum2.setKeySate("No");
				knum4.setKeySate("No");
				break;
			case 4:
				knum4.setPasswd(ssid.getWepKeyPassphrase());
				knum4.setType(ssid.getWepKeyFormat());
				knum4.setKfmt(ssid.getWepEncryptionLevel());
				knum4.setKeySate(ssid.getWepEncryptionLevel() != 0 ? "Yes" : "No");
				knum4.setAuthMethod(ssid.getWepEncryptionMode());
				knum1.setKeySate("No");
				knum2.setKeySate("No");
				knum3.setKeySate("No");
				break;
			default:
				break;
			}
			break;
		case 2:
			wpa.setRadiusIp(ssid.getRadiusServer());
			wpa.setRadiusPort(ssid.getRadiusPort());
			wpa.setRadiusPasswd(ssid.getRadiusKey());
			wpa.setUpdateTime(ssid.getWpakeyUpdateInterval());
			wpa.setwVersion(ssid.getWpaVersion());
			wpa.setWPAEncryptionModes(ssid.getWpaEncryptionMode());
			break;
		case 3:
			wpapsk.setwVersion(ssid.getWpaVersion());
			wpapsk.setSharePasswd(ssid.getWpakey());
			wpapsk.setUpdateTime(ssid.getWpakeyUpdateInterval());
			wpapsk.setWPAEncryptionModes(ssid.getWpaEncryptionMode());
			break;
		default:
			break;
		}
		wep.setKnum1(knum1);
		wep.setKnum2(knum2);
		wep.setKnum3(knum3);
		wep.setKnum4(knum4);
		sz.setWep(wep);
		sz.setWpa(wpa);
		sz.setWpaspsk(wpapsk);
		return sz;
	}

	@Override
	public JSONObject general(Device device) {
		String topic = MqttDeviceClientConfig.router(device.getSn());
		Get get = new Get();
		get.setId(Token.getToken());
		get.setReplyTo(Token.getToken());
		if(device.getType().equals("1") || device.getType().equals("1.1")){//router
			String[] params = new String[] { "system"};
			get.setData(JSON.toJSON(params));
		}else{
			String[] params = new String[] { "system", "net.lan", "net.wlan", "net.wan", "net.in", "net.out", "net.mqtt" };
			get.setData(JSON.toJSON(params));
		}
		JSONObject json = null;
		try {
			Message msg = rpcClient.callWithTimeout(topic, get, 5);
			GetResp getResp = (GetResp) msg;
			json = (JSONObject) getResp.getData();
		} catch (RPCException e) {
			e.printStackTrace();
		}
		return json;
	}

	@Override
	public List<GraphQueryResponse> visitorsRealTimeData(String sn,Timestamp bindtime, long start, long end) {
		List<GraphQueryResponse> sums = null;
		// 获取24小时内的历史数据，将返回的数据转换格式
		// 组装falcon-plus的查询参数
		end = System.currentTimeMillis() / 1000;
		start = end - 60 * 60 * 24;
		GraphQueryParam params = new GraphQueryParam();
		params.setStartTime(start);
		params.setEndTime(end - 60);
		params.setCounters(new String[] { "net.clients.client24g", "net.clients.client5g" });
		params.setStep(60);
		params.setHostNames(new String[] { sn });
		params.setConsolFun("AVERAGE");
		// 调用falcon-plus的api接口查询历史数据
		Client client = new Client();
		// 查询2.4G数据,查询5G数据
		String res = client.doPostWithJson("http://" + apiDiscovery.discover() + "/api/v1/graph/history",
				JSON.toJSONString(params));
		if (res != null && res.length() > 0) {
			// 合并数据，按counter合并
			List<GraphQueryResponse> resps = JSON.parseArray(res, GraphQueryResponse.class);
			sums = GraphUtils.MergeGraphDataByCounter(resps, false);
			if(sums!=null){
				for (GraphQueryResponse graphQueryResponse : sums) {
					//根据绑定时间筛选出设备数据,在绑定时间之前的数据都设置为0
					for (int k2 = 0; k2 < graphQueryResponse.getValues().size(); k2++) {
						if(bindtime.getTime()>graphQueryResponse.getValues().get(k2).getTimestamp()*1000){
							graphQueryResponse.getValues().get(k2).setValue(0.0);
						}
					}
				}
			}
			// 计算2.4g与5g的总数据
			sums.add(GraphUtils.countGraphDataByTimestamp(sums));
		}
		return sums;
	}

	@Override
	@doLog(description = Tips.LogRebootDevice, key = { "#device.name" })
	public RestResult restart(Device device) {
		RestResult res = new RestResult();
		String topic = MqttDeviceClientConfig.router(device.getSn());
		Reboot reboot = new Reboot();
		reboot.setId(Token.getToken());
		reboot.setDelay(5);
		reboot.setReplyTo(Token.getToken());
		try {
			Message msg = rpcClient.callWithTimeout(topic, reboot, 5);
			RebootResp resp = (RebootResp) msg;
			if (resp.getStatus() != 1) {
				System.out.println("resp:" + resp);
				res.setErrorCode(1);
				res.setErrorMsg("false");
				return res;
			}
		} catch (Exception e) {
			System.out.println("exception");
			e.printStackTrace();
			res.setErrorCode(1);
			res.setErrorMsg("false");
			return res;
		}
		return res;
	}

//	@Override
//	public boolean reset(Device device) {
//		String topic = MqttDeviceClientConfig.router(device.getSn());
//		Reset reset = new Reset();
//		reset.setId(Token.getToken());
//		reset.setReplyTo(Token.getToken());
//		try {
//			Message msg = rpcClient.callWithTimeout(topic, reset, 5);
//			ResetResp resp = (ResetResp) msg;
//			if (resp.getStatus() != 1) {
//				System.out.println("resp:" + resp);
//				return false;
//			}
//		} catch (Exception e) {
//			System.out.println("exception");
//			e.printStackTrace();
//			return false;
//		}
//		return true;
//	}
	
	@Override
	@doLog(description = Tips.LogResetDevice, key = { "" })
	public RestResult reset(List<Device> devices) {
		RestResult res = new RestResult();
		String errorMsg = "";
		int errorCode = 0;
		for (Device device : devices) {
			if (device.getStatus() == 0) {
				errorCode = 1;
				errorMsg += messageSourceUtil.getMessage(Tips.FailSn12).replaceAll("#", device.getSn())+"<br/>";
				continue;
			}else{
				if (device.getName() == null || device.getName() == "" || device.getName().length() == 0) {
					device.setName(device.getMac());
				}
				String topic = MqttDeviceClientConfig.router(device.getSn());
				Reset reset = new Reset();
				reset.setId(Token.getToken());
				reset.setReplyTo(Token.getToken());
				try {
					Message msg = rpcClient.callWithTimeout(topic, reset, 5);
					ResetResp resp = (ResetResp) msg;
					if (resp.getStatus() != 1) {
						System.out.println("resp:" + resp);
						errorCode = 0;
						errorMsg += "";
					}
				} catch (Exception e) {
					System.out.println("exception");
					e.printStackTrace();
					errorCode = 1;
					errorMsg += messageSourceUtil.getMessage(Tips.FailSn11).replaceAll("#", device.getSn()) + "</br>";
				}
			}
		}
		if (errorMsg == "" || errorMsg.length() == 0) {
			errorMsg = messageSourceUtil.getMessage(Tips.CmdSuccess);
		}
		res.setErrorCode(errorCode);
		res.setErrorMsg(errorMsg);
		return res;
		
	}

	@Override
	public List<GraphQueryResponse> packLoss(String sn, long start, long end) {
		List<GraphQueryResponse> sums = null;
		// 组装falcon-plus的查询参数
		end = System.currentTimeMillis() / 1000;
		start = end - 60 * 60;
		GraphQueryParam params = new GraphQueryParam();
		params.setStartTime(start);
		params.setEndTime(end - 60);
		params.setCounters(new String[] { "net.packets.lossrate24g", "net.packets.lossrate5g" });
		params.setStep(60);
		params.setHostNames(new String[] { sn });
		params.setConsolFun("AVERAGE");
		// 调用falcon-plus的api接口查询历史数据
		Client client = new Client();
		String res = client.doPostWithJson("http://" + apiDiscovery.discover() + "/api/v1/graph/history",
				JSON.toJSONString(params));
		if (res != null && res.length() > 0) {
			// 合并数据，按counter合并
			List<GraphQueryResponse> resps = JSON.parseArray(res, GraphQueryResponse.class);
			sums = GraphUtils.MergeGraphDataByCounter(resps, true);
			// 计算2.4g与5g的总数据
			sums.add(GraphUtils.countGraphDataByTimestamp(sums));
		}
		return sums;
	}

	@Override
	public List<GraphQueryResponse> packError(String sn, long start, long end) {
		List<GraphQueryResponse> sums = null;
		// 组装falcon-plus的查询参数
		end = System.currentTimeMillis() / 1000;
		start = end - 60 * 60;
		GraphQueryParam params = new GraphQueryParam();
		params.setStartTime(start);
		params.setEndTime(end - 60);
		params.setCounters(new String[] { "net.packets.errrate24g", "net.packets.errrate5g" });
		params.setStep(60);
		params.setHostNames(new String[] { sn });
		params.setConsolFun("AVERAGE");
		// 调用falcon-plus的api接口查询历史数据
		Client client = new Client();
		String res = client.doPostWithJson("http://" + apiDiscovery.discover() + "/api/v1/graph/history",
				JSON.toJSONString(params));
		if (res != null && res.length() > 0) {
			// 合并数据，按counter合并
			List<GraphQueryResponse> resps = JSON.parseArray(res, GraphQueryResponse.class);
			sums = GraphUtils.MergeGraphDataByCounter(resps, true);
			// 计算2.4g与5g的总数据
			sums.add(GraphUtils.countGraphDataByTimestamp(sums));
		}
		return sums;
	}


	@Override
	public void reUp(String sn, int connect, int delay) {
		System.out.println("disconnect指令：  " + connect);
		String topic = MqttDeviceClientConfig.router(sn);
		Disconnect disconnect = new Disconnect();
		disconnect.setId(Token.getToken());
		disconnect.setDelay(delay);
		disconnect.setConnect(connect);
		try {
			rpcClient.send(topic, disconnect);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public Map<String, Object> flowStatistics(long userId, Long networkId) {
		// 查询该局点下所有的设备
		Map<String, Device> infos = new HashMap<>();
		List<GraphLastParam> onlineparams = new ArrayList<>();
		List<Device> devices = queryDevicesByNetworkIds(new ArrayList<Long>() {
			{
				add(networkId);
			}
		});
		Map<String, Object> flow = new HashMap<>();
		long upFlow = 0l;
		long downFlow = 0l;
		for (Device device : devices) {
			infos.put(device.getSn(), device);
			GraphLastParam outBytes = new GraphLastParam();
			outBytes.setCounter("net.out.bytes");
			outBytes.setEndpoint(device.getSn());
			onlineparams.add(outBytes);
			GraphLastParam inBytes = new GraphLastParam();
			inBytes.setCounter("net.in.bytes");
			inBytes.setEndpoint(device.getSn());
			onlineparams.add(inBytes);
		}
		System.out.println(onlineparams);
		// 查询设备的在线状况
		Client client = new Client();
		String result = client.doPostWithJson("http://" + apiDiscovery.discover() + "/api/v1/graph/lastrawpoint",
				JSON.toJSONString(onlineparams));
		if (result != null && result.length() > 0) {
			List<GraphLastResp> resps = JSON.parseArray(result, GraphLastResp.class);
			if (resps != null) {
				for (GraphLastResp resp : resps) {
					Device info = infos.get(resp.getEndpoint());
					if (info == null || info.getStatus() == 0) {
						continue;
					}
					switch (resp.getCounter()) {
					case "net.out.bytes": // 下载流量
						upFlow += resp.getValue().getValue().longValue();
						break;
					case "net.in.bytes": // 上传流量
						downFlow += resp.getValue().getValue().longValue();
						break;
					default:
						break;
					}
				}
			}
		}
		flow.put("上传流量", upFlow);
		flow.put("下载流量", downFlow);
		return flow;
	}

	@Override
	@doLog(description = Tips.LogUpgradeFirmware, key = { "" })
	public RestResult batchUpdateSV(List<SoftVersion> svs, long userId, long groupId) {
		RestResult result = new RestResult();
		List<Long> ids = new ArrayList<>();
		Map<Long, Map<String, String>> parms = new HashMap<>();
		Map<String, Object> res = new HashMap<>();
		if (svs != null) {
			for (SoftVersion sv : svs) {
				Map<String, String> parm = new HashMap<>();
				parm.put("url", sv.getUrl());
				parm.put("version", sv.getVersion());
				parms.put(sv.getId(), parm);
				ids.add(sv.getId());
			}
		}
		System.out.println(JSON.toJSONString(ids));
		List<Device> devices = null;
		if (ids.size() > 0) {
			devices = deviceMapper.queryDevicesByIds(ids);
			if (!hasRights(devices, groupId)) {
				result.setErrorCode(-1);
				result.setErrorMsg(messageSourceUtil.getMessage(Tips.PermissionDenied));
				return result;
			}
		}
		if (devices != null) {
			CountDownLatch cb = new CountDownLatch(devices.size());
			for (Device device : devices) {
				String topic = MqttDeviceClientConfig.router(device.getSn());
				String url = parms.get(device.getId()).get("url");
				Download download = new Download();
				download.setId(Token.getToken());
				download.setReplyTo(Token.getToken());
				download.setFileType(0);
				download.setURL(url);
				download.setSoftVersion(parms.get(device.getId()).get("version"));
				download.setFilename(String.valueOf(System.currentTimeMillis()));
				int size = 0;
				try {
					size = UttTool.getFileLength(url);
				} catch (IOException e) {
					size = 0;
				}
				download.setFileSize(size); // 先为空
				download.setMD5(""); // 先为空
				download.setDelay(5);
				System.out.println("device:   " + JSON.toJSON(device));
				if (device.getStatus() == 1) {
					new Thread(new svThread1(cb, result, device.getSn(), topic, download)).start();
				} else {
					res.put("errorMsg", (res.get("errorMsg") != null ? res.get("errorMsg").toString() : "") + messageSourceUtil.getMessage(Tips.FailSn12).replaceAll("#", device.getSn()) + ".<br/>");
					cb.countDown();// 将cb线程数目减一
				}
			}
			try {
				cb.await();// 当cb为0时，启用
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (res.get("errorMsg") != null) {
			result.setErrorCode(1);
			if (result.getErrorMsg().length() > 0) {
				result.setErrorMsg(res.get("errorMsg").toString() + "<br/>"+messageSourceUtil.getMessage(Tips.UpCmdSuccess));
			} else {
				result.setErrorMsg(res.get("errorMsg").toString());
			}
		} else {
			result.setErrorMsg(messageSourceUtil.getMessage(Tips.UpCmdSuccess));
		}
		return result;
	}
	
	private class svThread1 implements Runnable {
		CountDownLatch _cb;
		RestResult result;
		String sn;
		String topic;
		cn.com.utt.common.message.Message message;

		public svThread1(CountDownLatch cb, RestResult result, String sn, String topic,
				cn.com.utt.common.message.Message message) {
			this._cb = cb;
			this.result = result;
			this.sn = sn;
			this.topic = topic;
			this.message = message;
		}

		@Override
		public void run() {
			try {
				DownloadResp res = (DownloadResp) rpcClient.callWithTimeout(topic, message, 5);
				if (res.getStatus() != 1) {
					synchronized (result) {
						result.setErrorCode(1);
						result.setErrorMsg(messageSourceUtil.getMessage(Tips.UpCmdSuccess));
					}
				} else {
					result.setErrorMsg(messageSourceUtil.getMessage(Tips.UpCmdSuccess));
				}
				_cb.countDown();
			} catch (Exception e) {
				synchronized (result) {
					result.setErrorCode(1);
					result.setErrorMsg(messageSourceUtil.getMessage(Tips.UpCmdSuccess));
					e.printStackTrace();
				}
				try {
					_cb.countDown();// 进程数目减一
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}
		}

	}

	@Override
	public RestResult bingDevice(Device device) {
		return null;
	}

	@Override
	public JSONObject wirelessExpansion(Device device) {
		String topic = MqttDeviceClientConfig.router(device.getSn());
		Get get = new Get();
		get.setId(Token.getToken());
		get.setReplyTo(Token.getToken());
		String[] params = new String[] {"ap.info"};
		get.setData(JSON.toJSON(params));
		JSONObject json = null;
		try {
			Message msg = rpcClient.callWithTimeout(topic, get, 5);
			GetResp getResp = (GetResp) msg;
			json = (JSONObject) getResp.getData();
		} catch (RPCException e) {
			e.printStackTrace();
		}
		return json;
	}

	@Override
	public JSONObject batchRfAndServiceZone(Device device) {
		String topic = MqttDeviceClientConfig.router(device.getSn());
		GetXml get = new GetXml();
		get.setId(Token.getToken());
		get.setReplyTo(Token.getToken());
		String[] params = new String[] {"apConfTemp","ServiceZone","dhcpPool"};
		get.setData(JSON.toJSON(params));
		JSONObject b = null;
		try {
			Message msg = rpcClient.callWithTimeout(topic, get, 5);
			GetXmlResp getResp = (GetXmlResp) msg;
			JSONObject json = (JSONObject) getResp.getData();
			String rfXml = json.getString("apConfTemp");
			String serviceZoneXml = json.getString("ServiceZone");
			String dhcpPoolXml = json.getString("dhcpPool");
			
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbFactory.newDocumentBuilder();
			Document document = null;
			
			b = new JSONObject();
//			HashSet<String> rfs = new HashSet<String>();
			List<JSONObject> serviceZones = new ArrayList<JSONObject>();
			List<Map<String, String>> rf = new ArrayList();
			
			// 获取地址池
			Map<Integer, String> vlanToAdress = new HashMap<Integer, String>();
			InputStream isDhcpPool = new ByteArrayInputStream(dhcpPoolXml.getBytes());
			document = db.parse(isDhcpPool);
			NodeList bookList = document.getElementsByTagName("case");
			for (int i = 0; i < bookList.getLength(); i++) {
				// 获取第i个book结点
				org.w3c.dom.Node node = bookList.item(i);
				// 获取第i个book的所有属性
				NamedNodeMap namedNodeMap = node.getAttributes();
				// 获取已知名为id的属性值
				String name = namedNodeMap.getNamedItem("name").getTextContent();// System.out.println(id);
				
				// 获取book结点的子节点,包含了Test类型的换行
				NodeList cList = node.getChildNodes();// System.out.println(cList.getLength());9

				for (int j = 1; j < cList.getLength(); j += 2) {
					org.w3c.dom.Node cNode = cList.item(j);
					if (cNode.getNodeName().equals("vid")) {
						vlanToAdress.put(Integer.parseInt(cNode.getTextContent()), name);
					}
				}
			}
			
			System.out.println(JSON.toJSONString(vlanToAdress));
			
			// 获取射频模板
			InputStream isRf = new ByteArrayInputStream(rfXml.getBytes());
			document = db.parse(isRf);
			bookList = document.getElementsByTagName("case");
			for (int i = 0; i < bookList.getLength(); i++) {
				Map<String, String> c =new HashMap<>();
				// 获取第i个book结点
				org.w3c.dom.Node node = bookList.item(i);
				// 获取第i个book的所有属性
				NamedNodeMap namedNodeMap = node.getAttributes();
				// 获取已知名为id的属性值
				String name = namedNodeMap.getNamedItem("name").getTextContent();// System.out.println(id);
				c.put("name", name);
				NodeList cList = node.getChildNodes();
				for (int j = 1; j < cList.getLength(); j ++) {
					org.w3c.dom.Node cNode = cList.item(j);
					if (cNode.getNodeName().equals("channel")) {
						c.put("channel", name+"_"+cNode.getTextContent());
					}
					if (cNode.getNodeName().equals("en_channel")) {
						c.put("en_channel", cNode.getTextContent());
					}
					if (cNode.getNodeName().equals("wireless")) {
						c.put("wireless", cNode.getTextContent());
					}
				}
//				rfs.add(name.substring(0,name.length()-2));
				rf.add(c);
			}
			List<Map<String, String>> rfs=new ArrayList<>();
			rfs=mergeBatchModelRf(rf);
			b.put("Rf",rfs);
			
			// 获取网络名称
			InputStream isServiceZone = new ByteArrayInputStream(serviceZoneXml.getBytes());
			document = db.parse(isServiceZone);
			bookList = document.getElementsByTagName("case");
			for (int i = 0; i < bookList.getLength(); i++) {
				JSONObject c = new JSONObject();
				// 获取第i个book结点
				org.w3c.dom.Node node = bookList.item(i);
				// 获取第i个book的所有属性
				NamedNodeMap namedNodeMap = node.getAttributes();
				// 获取已知名为id的属性值
				String name = namedNodeMap.getNamedItem("name").getTextContent();// System.out.println(id);
				c.put("zoneName", name);

				// 获取book结点的子节点,包含了Test类型的换行
				NodeList cList = node.getChildNodes();// System.out.println(cList.getLength());9
				// 将一个book里面的属性加入数组
				for (int j = 1; j < cList.getLength(); j ++) {

					org.w3c.dom.Node cNode = cList.item(j);
					if (cNode.getNodeName().equals("ssid")) {
						c.put("ssid", cNode.getTextContent());
					}
					if (cNode.getNodeName().equals("vid")) {
						c.put("vlanId", cNode.getTextContent());
						c.put("dhcpPoolName", vlanToAdress.get(Integer.parseInt(cNode.getTextContent())));
					}
				}
				serviceZones.add(c);
			}
			b.put("ServiceZone", serviceZones);
			System.out.println(JSON.toJSONString(b));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return b;
	}

	@Override
	@doLog(description = Tips.LogRebootDevice, key = { "" })
	public RestResult restarts(List<Device> devices) {
		RestResult res = new RestResult();
		String errorMsg = "";
		int errorCode = 0;
		for (Device device : devices) {
			if (device.getStatus() == 0) {
				errorCode = 1;
				errorMsg += messageSourceUtil.getMessage(Tips.FailSn12).replaceAll("#", device.getSn())+"<br/>";
				continue;
			}else{
				if (device.getName() == null || device.getName() == "" || device.getName().length() == 0) {
					device.setName(device.getMac());
				}
				String topic = MqttDeviceClientConfig.router(device.getSn());
				Reboot reboot = new Reboot();
				reboot.setId(Token.getToken());
				reboot.setDelay(5);
				reboot.setReplyTo(Token.getToken());
				try {
					Message msg = rpcClient.callWithTimeout(topic, reboot, 5);
					RebootResp resp = (RebootResp) msg;
					if (resp.getStatus() != 1) {
						System.out.println("resp:" + resp);
						errorCode = 0;
						errorMsg += "";
						}
				} catch (Exception e) {
					System.out.println("exception");
					e.printStackTrace();
					errorCode = 1;
					errorMsg += messageSourceUtil.getMessage(Tips.FailSn11).replaceAll("#", device.getSn()) + "</br>";
				}
			}
		}
		if (errorMsg == "" || errorMsg.length() == 0) {
			errorMsg = messageSourceUtil.getMessage(Tips.CmdSuccess);
		}
		res.setErrorCode(errorCode);
		res.setErrorMsg(errorMsg);
		return res;
		
	}
	
	
	public List<Map<String,String>> mergeBatchModelRf(List<Map<String, String>> rf){
//		LinkedHashSet<String> ss=new LinkedHashSet<String>();
		List<Map<String,String>> rfs=new ArrayList<>();
		Map<String,String> hh=null;
		  if(rf.size()>0){
			  for (int i = 0; i < rf.size(); i++) {
				  hh=new HashMap<>();
				  String str="";
				  String ichannel=rf.get(i).get("channel");
				  String ic0=ichannel.split("_")[0];
				  String ic1=ichannel.split("_")[1];
				  String ic2=ichannel.split("_")[2];
				  String ienchannel=rf.get(i).get("en_channel");
				  String iwireless=rf.get(i).get("wireless");//wireless无线功能:Enable开启     Disable关闭
				  //en_channel为0   信道 不下发   ; en_channel为1   信道 下发  channel为0 信道自动;en_channel为1   信道 下发  channel 不为0 则表示信道值
				  if(iwireless.equals("Disable")){//无线功能关闭
					  ic2="";
				  }else{
					  if(ienchannel.equals("0")){//信道不下发
						  ic2="不下发";
					  }else if(ienchannel.equals("1")){//信道下发
						  if(ic2.equals("0")){
							  ic2="自动";
						  }
					  }
				  }
				 for(int j = i+1; j < rf.size(); j++){
					 String jc0=rf.get(j).get("channel").split("_")[0];
					 String jc1=rf.get(j).get("channel").split("_")[1];
					 String jc2=rf.get(j).get("channel").split("_")[2];
					 String jenchannel=rf.get(j).get("en_channel");
					 String jwireless=rf.get(j).get("wireless");
					 if(jwireless.equals("Disable")){//无线功能关闭
						  jc2="";
					 }else{
						 if(jenchannel.equals("0")){//信道不下发
							  jc2="不下发";
						  }else if(jenchannel.equals("1")){//信道下发
							  if(jc2.equals("0")){
								  jc2="自动";
							  }
						  }
					 }
					 if(ic0.equals(jc0)){//模板名称一致
						 if(!ic1.equals(jc1)){
							 if(ic1.equals("4")){
								 String tems="（信道："+ic2+"/"+jc2+"）";
								 if(iwireless.equals("Disable")&&jwireless.equals("Disable")){//无线功能关闭
									 tems="";
								  }
								 str=ic0+tems;
							 }else{
								 String tems="（信道："+jc2+"/"+ic2+"）";
								 if(iwireless.equals("Disable")&&jwireless.equals("Disable")){//无线功能关闭
									 tems="";
								  }
								 str=ic0+tems;
							 }
						 }
						i=j;
//						ss.add(str); 
						hh.put("name", ic0);
						hh.put("value", str);
						rfs.add(hh);
						break;
					 }
				 }
			}
		  }
		  return rfs;
	}
}